Including local JS modules
👀 Reading hidden code
Sample ES6 project
Create a sample folder and populate it with some JS modules:
👀 Reading hidden code
"/tmp/jl_yGFAHR"
👀 Reading hidden code
source_folder = begin
f = mktempdir()
import { cool } from "./cool.js"
import { also_cool } from "./also/cool.js"
export const hello = (x) => [cool(x), also_cool(x)]
""")
// I can import from URLs, they will join the bundle:
import _ from "https://cdn.esm.sh/v58/lodash-es@4.17.21/es2021/lodash-es.js"
export let cool = x => _.repeat("hello ", x)
""")
export let also_cool = (x) => " world!"
""")
end
"also"
"cool.js"
"index.js"
readdir(f)
👀 Reading hidden code
"/tmp/jl_yGFAHR/index.js"
input_file = joinpath(source_folder, "index.js")
👀 Reading hidden code
Bundle
Try changing the code in one of the JS files in the first section (above), and the bundler will automatically re-run!
👀 Reading hidden code
import Deno_jll: deno
👀 Reading hidden code
"var __global\$ = globalThis || (typeof window !== \"undefined\" ? window : self);\nvar wd = typeof __global\$ == \"object\" && __global\$ && __global\$.Object === Object && __global\$, Eo = wd;\nvar Ld = typeof self == \"object\" && self && self.Object === Object && self, Ed = Eo || Ld || Function(\"return thi" ⋯ 128737 bytes ⋯ "Of = i.prototype.value = Kr.value;\ni.prototype.first = i.prototype.head;\nRd && (i.prototype[Rd] = Kr.toIterator);\nvar PE = i;\nlet cool = (x)=>PE.repeat(\"hello \", x)\n;\nlet also_cool = (x)=>\" world!\"\n;\nconst hello1 = (x)=>[\n cool(x),\n also_cool(x)\n ]\n;\nexport { hello1 as hello };\n\n"
bundle_code = begin
error_file = tempname()
try
read(pipeline(`$(deno()) bundle $(input_file)`, stderr=error_file), String)
catch e
if e isa ProcessFailedException
@htl("""
<h4>❌ Bundle failed</h4>
<pre><code>$(read(error_file, String))</code></pre>
""")
else
rethrow(e)
end
end
end
👀 Reading hidden code
Use it inside code
👀 Reading hidden code
@bind x Slider(1:1000)
👀 Reading hidden code
hello world!
my_widget(x)
👀 Reading hidden code
Deprecated, use `AbstractPlutoDingetjes.Display.published_to_js(x)` instead of `PlutoRunner.publish_to_js(x)`.
my_widget (generic function with 1 method)
function my_widget(x)
@htl("""
<script>
const { hello } = $(import_local_js(bundle_code))
let result = hello($(x))
return html`<span>\${result}</span>`
</script>
""")
end
👀 Reading hidden code
Magic
We use publish_to_js
to make the string available to JS running in the cell output. Inside the JS, we turn the string into a blob URL and call import()
on that.
We create a Map
, called window.created_imports
, to keep track of strings that we already imported. When you re-import the same string a second time, the original import result is retured.
👀 Reading hidden code
import_local_js (generic function with 1 method)
function import_local_js(code::AbstractString)
code_js =
try
Main.PlutoRunner.publish_to_js(code)
catch
repr(code)
end
HypertextLiteral.JavaScript(
"""
await (() => {
window.created_imports = window.created_imports ?? new Map()
let code = $(code_js)
if(created_imports.has(code)){
return created_imports.get(code)
} else {
let blob_promise = new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = async () => {
try {
resolve(await import(reader.result))
} catch(e) {
reject()
}
}
reader.onerror = () => reject()
reader.onabort = () => reject()
reader.readAsDataURL(
new Blob([code], {type : "text/javascript"}))
})
created_imports.set(code, blob_promise)
return blob_promise
}
})()
"""
)
end
👀 Reading hidden code
Other attempts
👀 Reading hidden code
"console.log(\"I should run only once!\")\n\nexport const x = 345\n"
code = """
console.log("I should run only once!")
export const x = 345
"""
👀 Reading hidden code
using Base64
👀 Reading hidden code
"data:text/javascript;base64,Y29uc29sZS5sb2coIkkgc2hvdWxkIHJ1biBvbmx5IG9uY2UhIikKCmV4cG9ydCBjb25zdCB4ID0gMzQ1Cg=="
base64url = "data:text/javascript;base64,$(base64encode(code))"
👀 Reading hidden code
@htl("""
<script>
const { x } = await import($(base64url))
console.log(x)
</script>
""")
👀 Reading hidden code
@htl("""
<script>
const {x} = $(import_local_js(code2))
console.log(x)
</script>
""")
👀 Reading hidden code
Deprecated, use `AbstractPlutoDingetjes.Display.published_to_js(x)` instead of `PlutoRunner.publish_to_js(x)`.
"console.log(\"I should run only once!\")\n\nexport const x = 32\n"
code2 = """
console.log("I should run only once!")
export const x = 32
"""
👀 Reading hidden code
using PlutoUI
👀 Reading hidden code
@bind x2 Slider(1:1000)
👀 Reading hidden code
1
@htl("""
<script>
const x = $(PlutoRunner.publish_to_js(x2))
return html`<span>\${x}</span>`
</script>
""")
👀 Reading hidden code
Deprecated, use `AbstractPlutoDingetjes.Display.published_to_js(x)` instead of `PlutoRunner.publish_to_js(x)`.
using HypertextLiteral
👀 Reading hidden code